
#include <string.h>

#include "stm32l4xx.h"
#include "stm32l4xx_ll_bus.h"
#include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_ll_lpuart.h"
#include "stm32l4xx_ll_usart.h"

#include "bsp_modbus.h"
#include "bsp.h"


#define UART_RS485					LPUART1
#define UART_RS485_IRQn				LPUART1_IRQn
#define UART_RS485_IRQHandler 		LPUART1_IRQHandler

#define UART_PLC					UART_RS485
#define UART_PLC_IRQn				LPUART1_IRQn
#define UART_PLC_IRQHandler 		LPUART1_IRQHandler

////作废
//#define MODE_7_E_1								0
//#define MODE_7_O_1								1
//#define MODE_8_E_1								2
//#define MODE_8_O_1								3
//#define MODE_8_n_1								4
//#define MODE_8_n_2								5



static void bsp_uart_plc_hal(void);


typedef struct _UART_CFG{
	uint32_t baud;		//9600/19200/38400/57600
	char fmt[7];		//6个字符和1个'\0'。6个字符对应6个数码管。
	uint8_t sta;		//当前状态（0--关闭，1--打开）
}UART_CFG;

UART_CFG uart_plc_cfg={9600, FMT_8_n_1, 0};

const uint32_t _tbl_plc_baud[]= {9600,19200,38400,57600,115200, -1};
const char* _tbl_plc_fmt[]= {FMT_8_E_1, FMT_8_O_1, FMT_8_n_1, FMT_8_n_2, ""};


/*设置与PLC相连串口的数据格式、波特率和当前状态。
*/
void bsp_uart_plc_config(const char* fmt, uint32_t baud, uint8_t sta)
{
	uint32_t pclk1_clock;
	uint32_t baud_rate;
	

	baud_rate= baud;
	
	if(baud_rate< 19200){	
		//使能HSI，并等待稳定。
		LL_RCC_HSI_Enable();
		while(0 == LL_RCC_HSI_IsReady()){}	//不能使用LL_RCC_IsActiveFlag_HSIRDY()。
			
		LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_HSI);
		//pclk1_clock= 16000000;	//没找到更合适的函数，暂直接指定值。
	}
	else{
		LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_SYSCLK);
		//pclk1_clock= 48000000;
	}	
	
	pclk1_clock= LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE);		//QQ可以取代上面的直接赋值语句。
	LL_LPUART_SetBaudRate(UART_PLC, pclk1_clock, uart_plc_cfg.baud); 

	
	if(0 != uart_plc_cfg.sta){
		//先将LPUART1关闭。
		LL_LPUART_Disable(UART_PLC);
	}
	
	//修改数据格式（校验位，停止位）时，须处于串口关闭状态。This bit field can only be written when the USART is disabled (UE=0).
	if(0){
	}
	else if(0 == strcmp(fmt, FMT_8_E_1)){
		LL_USART_ConfigCharacter(UART_PLC, LL_USART_DATAWIDTH_9B, LL_USART_PARITY_EVEN, LL_USART_STOPBITS_1);	//奇偶校验时，数据宽度须为9B。
	}
	else if(0 == strcmp(fmt, FMT_8_O_1)){
		LL_USART_ConfigCharacter(UART_PLC, LL_USART_DATAWIDTH_9B, LL_USART_PARITY_ODD, LL_USART_STOPBITS_1);	//奇偶校验时，数据宽度须为9B。
	}
	else if(0 == strcmp(fmt, FMT_8_n_1)){
		LL_USART_ConfigCharacter(UART_PLC, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
	}
	else if(0 == strcmp(fmt, FMT_8_n_2)){
		LL_USART_ConfigCharacter(UART_PLC, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_2);
	}
	else{	//默认：FMT_8_n_1...
		LL_USART_ConfigCharacter(UART_PLC, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
	}
	

	
	if(0 == uart_plc_cfg.sta){
		//先将LPUART1关闭。
		LL_LPUART_Enable(UART_PLC);
	}
	
	UART_PLC_RX;
	
	//根据波特率，设定接收超时时间（暂统一）
	modbus_recv_info.tmo_max= 500;	//500ms
}



static void bsp_uart_plc_hal(void)
{
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD);
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

	/*
	TXEN	Pin54/PD2	高电平时，数据在输出。
	TX	Pin30/PB11	LPUART1。
	RX	Pin29/PB10	LPUART1。
	*/
	LL_GPIO_SetPinOutputType(GPIOD, LL_GPIO_PIN_2,LL_GPIO_OUTPUT_PUSHPULL);
	LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_2, LL_GPIO_MODE_OUTPUT);
	UART_PLC_RX;
	
	
	LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_11, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetAFPin_8_15(GPIOB, LL_GPIO_PIN_11, LL_GPIO_AF_8);				//C AF8 as L LPUART1_TX.
	
	LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_10, LL_GPIO_PULL_UP);
	LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_10, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetAFPin_8_15(GPIOB, LL_GPIO_PIN_10, LL_GPIO_AF_8);				//C AF8 as L LPUART1_RX.
}



/*配置MCU和PLC相连的串口。
!!需要开启相应时钟。
*/
void bsp_uart_plc_init(uint32_t baud, const char* fmt)
{
	bsp_uart_plc_hal();
	
	LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
	LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_SYSCLK);	//PCLK as LPUART1's clock source,!!Must enable LPUART1_EN@RCC_APB1ENR2.
	
	LL_USART_Disable(UART_PLC);	//因为会动态修改该串口参数，所以假定它处于使能状态，需先禁止。
	
	/*配置串口：中断接收，查询发送。
	帧格式：
	7-E-1：7 位数据位，偶校验，1 位停止位；
	7-O-1：7 位数据位，奇校验，1 位停止位；
	8-E-1：8 位数据位，偶校验，1 位停止位；
	8-O-1：8 位数据位，奇校验，1 位停止位；
	8-n-1：8 位数据位，无校验，1 位停止位；
	8-n-2：8 位数据位，无校验，2 位停止位；
	波特率：
	0  9600");
	1  19200");
	2  38400");
	3  57600");
	*/
//	if(0 == mode)
//		uart_rs485_cfg.mode= MODE_7_E_1;
//	else if(1 == mode)
//		uart_rs485_cfg.mode= MODE_7_O_1;
//	else if(2 == mode)
//		uart_rs485_cfg.mode= MODE_8_E_1;
//	else if(3 == mode)
//		uart_rs485_cfg.mode= MODE_8_O_1;
//	else if(4 == mode)
//		uart_rs485_cfg.mode= MODE_8_n_1;
//	else if(5 == mode)
//		uart_rs485_cfg.mode= MODE_8_n_2;
//	else
//		uart_rs485_cfg.mode= MODE_8_n_1;
//	
//	if( (9600 != baud)  &&
//		(19200 != baud) &&
//		(38400 != baud) &&
//		(57600 != baud))
//		uart_rs485_cfg.baud= 9600;	
//	else
//		uart_rs485_cfg.baud= (uint16_t)baud;
//	
	uart_plc_cfg.baud= baud;
	strcpy(uart_plc_cfg.fmt, fmt);	
	uart_plc_cfg.sta= 0;
	
	//C OVER8@CR1=0, 16 samples.
	/* baudrate= fck/(8*(2-OVER8)*UARTDIV). UARTDIV= man.fra.
	例fpclk=84MHz，16samples，115200时，man.fra=45.5625，即0x2D9。
	具体参考RM0090's P978。
	*/
	bsp_uart_plc_config(uart_plc_cfg.fmt, uart_plc_cfg.baud, 0);	//9600/19200/38400/57600

	
	LL_USART_EnableDirectionTx(UART_PLC);
	LL_USART_EnableDirectionRx(UART_PLC);
	LL_USART_Enable(UART_PLC);
	
	LL_USART_EnableIT_RXNE(UART_PLC);
	
	
	/* preemption = 1, sub-priority = 1 */
	NVIC_SetPriority(UART_PLC_IRQn, 1);
	/* Enable Interrupt for UART0 channel */
	NVIC_EnableIRQ(UART_PLC_IRQn);
}

/************************ END OF FILE ************************/
